use actix_web::{web, HttpRequest, HttpResponse, Result};
use sea_orm::{DatabaseTransaction, IntoActiveModel, TryIntoModel};
use serde_json;

use crate::{
    entities::policy_db_model::ActiveModel,
    handler::policy_handler::PolicyHandler,
    policy_error::policy_error::PolicyError,
    repositories::policy_repository::PolicyRepository,
    util::{parameter_filter::ParameterFilter, policy_util::PolicyUtil},
};
use attestation_common::log::{error, info};

pub struct PolicyService;
impl PolicyService {
    /// Adds a new policy to the system.
    ///
    /// # Arguments
    /// * `req` - The HTTP request containing headers with user information
    /// * `db` - Database transaction for atomic operations
    /// * `request_body` - JSON payload containing policy details with required fields:
    ///   - name: Policy name
    ///   - description: Policy description
    ///   - attester_type: Type of attester
    ///   - content_type: Type of content (jwt or text)
    ///   - content: Policy content
    ///
    /// # Returns
    /// * `Ok((HttpResponse, DatabaseTransaction))` - Success response with policy ID, name, and version
    /// * `Err(PolicyError)` - Various error types including validation, database, or signing errors
    pub async fn add_policy(
        req: HttpRequest,
        db: DatabaseTransaction,
        request_body: web::Json<serde_json::Value>,
    ) -> Result<(HttpResponse, DatabaseTransaction), PolicyError> {
        info!("Handling request to add policy");
        let required_fields = vec!["name", "attester_type", "content_type", "content"];
        ParameterFilter::validate_policy_request(&request_body, &required_fields)?;
        // TODO:
        // 1. 判断是否需要对入参中content_type为jwt的签名进行证书验签，如果需要，则进行验签，否则不验签；如果为text但配置需要验签，则直接返回失败(400)
        // 2. 获取插件
        // 3. 获取插件的样例输出
        // 4. 使用策略引擎对样例输出进行匹配，如果语法有错误，直接返回失败(400)
        let headers = req.headers();
        let policy = match PolicyHandler::create_policy(headers, &request_body, &db).await {
            Ok(policy) => policy,
            Err(e) => {
                error!("Failed to create policy: {:?}", e);
                return Err(e);
            }
        };
        let mut policy_model = PolicyHandler::create_policy_model(headers, &policy);
        let is_require_sign = PolicyUtil::get_bool_yaml_config(
            "attestation_service.attestation_verifier.is_require_sign",
            false,
        );
        if is_require_sign {
            policy_model = ActiveModel::from(
                PolicyHandler::sign_policy(policy_model.into_active_model())
                    .await
                    .map_err(|e| e)?
                    .try_into_model()
                    .unwrap(),
            );
        }
        match PolicyRepository::add_policy(&db, policy_model).await {
            Ok(_) => {
                info!("Policy added successfully");
                Ok((
                    HttpResponse::Ok().json(serde_json::json!({
                        "id": policy.id,
                        "name": policy.name,
                        "version": policy.version
                    })),
                    db,
                ))
            }
            Err(e) => {
                error!("Failed to add policy: {:?}", e);
                Err(PolicyError::DatabaseOperationError(e.to_string()))
            }
        }
    }

    /// Updates an existing policy in the system.
    ///
    /// # Arguments
    /// * `req` - The HTTP request containing headers with user information
    /// * `db` - Database transaction for atomic operations
    /// * `request_body` - JSON payload containing policy update details with required field:
    ///   - id: Policy ID to update
    ///
    /// # Returns
    /// * `Ok((HttpResponse, DatabaseTransaction))` - Success response with updated policy ID, name, and version
    /// * `Err(PolicyError)` - Various error types including not found, validation, database, or signing errors
    pub async fn update_policy(
        req: HttpRequest,
        db: DatabaseTransaction,
        request_body: web::Json<serde_json::Value>,
    ) -> Result<(HttpResponse, DatabaseTransaction), PolicyError> {
        info!("Handling request to update policy");
        let required_fields = vec!["id"];
        ParameterFilter::validate_policy_request(&request_body, &required_fields)?;
        let headers = req.headers();
        let policy = match PolicyRepository::check_policy_exists(headers, &db, &request_body).await
        {
            Ok(None) => {
                error!("Policy not found!");
                return Err(PolicyError::PolicyNotFoundError(
                    "Policy not found".to_string(),
                ));
            }
            Ok(Some(policy)) => policy,
            Err(e) => {
                error!("Database error when checking policy existence: {:?}", e);
                return Err(PolicyError::DatabaseOperationError(e.to_string()));
            }
        };

        let update_model =
            match PolicyHandler::build_update_model(&request_body, &db, &policy).await {
                Ok(model) => model,
                Err(e) => {
                    error!("Failed to build update model: {:?}", e);
                    return Err(PolicyError::IncorrectFormatError(e.to_string()));
                }
            };
        let update_model =
            match PolicyHandler::verify_and_sign_policy(&db, &policy, update_model).await {
                Ok(model) => model,
                Err(PolicyError::PolicySignatureFailure(msg)) => {
                    return Ok((
                        HttpResponse::BadRequest().json(serde_json::json!({
                            "message": msg
                        })),
                        db,
                    ));
                }
                Err(e) => return Err(e),
            };
        match PolicyRepository::update_policy(&db, update_model).await {
            Ok(updated_policy) => {
                info!(
                    "Policy {} updated successfully. Version: {}",
                    updated_policy.id, updated_policy.version
                );
                Ok((
                    HttpResponse::Ok().json(serde_json::json!({
                        "id": updated_policy.id,
                        "name": updated_policy.name,
                        "version": updated_policy.version
                    })),
                    db,
                ))
            }
            Err(e) => {
                error!("Failed to update policy: {:?}", e);
                Err(PolicyError::DatabaseOperationError(e.to_string()))
            }
        }
    }

    /// Deletes one or more policies from the system.
    ///
    /// # Arguments
    /// * `req` - The HTTP request containing headers with user information
    /// * `db` - Database transaction for atomic operations
    /// * `request_body` - JSON payload containing required field:
    ///   - ids: Array of policy IDs to delete
    ///
    /// # Returns
    /// * `Ok((HttpResponse, DatabaseTransaction))` - Success response with empty body
    /// * `Err(PolicyError)` - Various error types including validation or database errors
    pub async fn delete_policy(
        req: HttpRequest,
        db: DatabaseTransaction,
        request_body: web::Json<serde_json::Value>,
    ) -> Result<(HttpResponse, DatabaseTransaction), PolicyError> {
        info!("Handling request to delete policy");
        let required_fields = vec!["delete_type"];
        ParameterFilter::validate_policy_request(&request_body, &required_fields)?;
        let user_id = req
            .headers()
            .get("user_id")
            .and_then(|h| h.to_str().ok())
            .unwrap_or("system")
            .to_string();

        let delete_type = request_body["delete_type"].as_str().ok_or_else(|| {
            PolicyError::IncorrectFormatError("delete_type must be a string".to_string())
        })?;

        let result = match delete_type {
            "id" => {
                let policy_ids: Vec<String> = request_body["ids"]
                    .as_array()
                    .ok_or_else(|| {
                        PolicyError::IncorrectFormatError("ids must be an array".to_string())
                    })?
                    .iter()
                    .filter_map(|v| v.as_str().map(String::from))
                    .collect();
                PolicyRepository::delete_policies(&db, policy_ids, user_id).await
            }
            "attester_type" => {
                let attester_type = request_body["attester_type"]
                    .as_str()
                    .ok_or_else(|| {
                        PolicyError::IncorrectFormatError(
                            "attester_type must be a string".to_string(),
                        )
                    })?
                    .to_string();
                PolicyRepository::delete_policies_by_type(&db, attester_type, user_id).await
            }
            "all" => PolicyRepository::delete_all_policies(&db, user_id).await,
            _ => Err(PolicyError::IncorrectFormatError(
                "Invalid delete_type".to_string(),
            )),
        };

        match result {
            Ok(()) => {
                info!("Policies deleted successfully");
                Ok((HttpResponse::Ok().finish(), db))
            }
            Err(e) => {
                error!("Failed to delete policies: {:?}", e);
                Err(e)
            }
        }
    }

    /// Queries policies based on different criteria.
    ///
    /// # Arguments
    /// * `req` - The HTTP request containing headers with user information
    /// * `db` - Database transaction for atomic operations
    /// * `query_params` - JSON payload containing optional query parameters:
    ///   - ids: Array of policy IDs to query specific policies
    ///   - attester_type: Query policies by attester type
    ///
    /// # Returns
    /// * `Ok((HttpResponse, DatabaseTransaction))` - Success response with array of matching policies
    /// * `Err(PolicyError)` - Various error types including validation or database errors
    pub async fn query_policy(
        req: HttpRequest,
        db: DatabaseTransaction,
        query_params: web::Json<serde_json::Value>,
    ) -> Result<(HttpResponse, DatabaseTransaction), PolicyError> {
        info!("Handling request to query policy");
        let user_id = req
            .headers()
            .get("user_id")
            .and_then(|h| h.to_str().ok())
            .unwrap_or("system")
            .to_string();
        info!("{:?}", query_params);
        let mut response = serde_json::Map::new();
        let user_policy_query_limit = PolicyUtil::get_u64_yaml_config(
            "attestation_service.attestation_verifier.query_user_policy_limit",
            10,
        );
        let policies_json: Vec<serde_json::Value>;

        if let Err(e) = ParameterFilter::validate_query_params(&query_params) {
            error!("Invalid query parameters: {}", e);
            return Err(e);
        }

        if query_params.get("ids").is_some() {
            let policies =
                PolicyHandler::query_policies_by_ids(&db, &query_params, user_id).await?;
            policies_json = policies.iter().map(|p| p.to_full_json()).collect();
            if policies_json.len() > user_policy_query_limit as usize {
                response.insert("message".to_string(), serde_json::Value::String(
                    "The queried policy list is larger than the upper limit configured for a single user".to_string()
                ));
                response.insert(
                    "policies".to_string(),
                    serde_json::Value::Array(
                        policies_json[..user_policy_query_limit as usize].to_vec(),
                    ),
                );
            } else {
                response.insert(
                    "policies".to_string(),
                    serde_json::Value::Array(policies_json.clone()),
                );
            }
        } else if query_params.get("attester_type").is_some() {
            let policies =
                PolicyHandler::query_policies_by_type(&db, &query_params, user_id).await?;
            policies_json = policies.iter().map(|p| p.to_base_json()).collect();
            response.insert(
                "policies".to_string(),
                serde_json::Value::Array(policies_json.clone()),
            );
        } else {
            let policies = PolicyHandler::get_all_policies(&db, user_id).await?;
            policies_json = policies.iter().map(|p| p.to_base_json()).collect();
            response.insert(
                "policies".to_string(),
                serde_json::Value::Array(policies_json.clone()),
            );
        }

        Ok((HttpResponse::Ok().json(response), db))
    }
}
